import re
from datetime import datetime

import gdata
from gdata.youtube.service import YouTubeService,YouTubeVideoQuery

from engine import parse_info

youtube_service = YouTubeService()

YOUTUBE_DATE_FORMAT = '%Y-%m-%dT%H:%M:%S.000Z'
YOUTUBE_URL_REGEX = re.compile('http://www.youtube.com/watch\?v=([\w-]{11})')
                    

def build_details_dictionary(entry):
    """
    Builds a dictionary of important items from a YouTube video entry object.
    """
    result = {}
    result['title'] = entry.title.text
    result['description'] = entry.media.description.text or ''
    result['video_id'] = YOUTUBE_URL_REGEX.findall(entry.link[0].href)[0]
    result['author'] = entry.author[0].name.text
    result['published_date'] = datetime.strptime(entry.published.text,
            YOUTUBE_DATE_FORMAT)

    return result

def parse_details(title, description, author):
    return parse_info(title, description, author)

def get_youtube_video(youtube_id):
    result = youtube_service.GetYouTubeVideoEntry(video_id=youtube_id)
    return build_details_dictionary(result)

def get_author_videos(author_name, start_date, end_date):
    def make_query(query):
        query.author = author_name

    return run_youtube_search(make_query, start_date, end_date)

def get_author_query_videos(author_name, query_text):
    def make_query(query):
        query.author = author_name
        query.vq = query_text

    return run_youtube_search(make_query)

def get_starcraft_videos(start_date, end_date):
    def make_query(query):
        query.vq = 'starcraft'

    return run_youtube_search(make_query, start_date, end_date)

def run_youtube_search(make_query,
        start_date=datetime(2000,1,1),
        end_date=datetime(2525,1,1)):
    """
    Will search youtube videos for a query, returning the entry of each
    video that falls within that date.

    Note that this can take a reaaaally long time, so large spans are not
    recommended.

    handler: an object which has a "handle_entry" and "finish" method.
    start_date: The start of a span of time that a video must be within to be
    considered a valid entry.
    end_date: The end of a span of time that a video must be within to be
    considered a valid entry.

    TODO: Change the algorithm to have a better chance of finding the first
    video we're looking for. Right now, if we start at some date three years
    ago, this baby will run all week skipping over the first few results.
    Eventually, the algorithm should work like a binary search algorithm. Or, if
    the query will probably remain constant, have a lookup table of dates so
    that the first guess can be a bit better.

    Also, need to consider the effect of new videos added (will videos be
    skipped/repeated in the results when the new video offsets the old videos?)
    """

    if start_date > end_date:
        raise ValueError("start_date must be a time before end_date")

    current_index = 1
    page_size = 50
    found_end = False
    results = []

    q = YouTubeVideoQuery()
    make_query(q)
    q.max_results = page_size
    q.orderby = 'published'

    while True:
        q.start_index = str(current_index)
        r = youtube_service.YouTubeQuery(q)

        for entry in r.entry:
            published_date = datetime.strptime(entry.published.text,
                    YOUTUBE_DATE_FORMAT)
                    

            if published_date < start_date:
                found_end = True
                break

            if published_date > end_date:
                continue

            results.append(entry)

        current_index += page_size
        total_results = int(r.total_results.text)

        if current_index > total_results or found_end:
            break

    return [build_details_dictionary(x) for x in results]
